package com.audaque.springboot.foshanupload.log.listener;


import com.audaque.springboot.foshanupload.log.model.MdcInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.GenericApplicationListener;
import org.springframework.core.Ordered;
import org.springframework.core.ResolvableType;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;

/**
 * SpringBoot事件的监听器
 * <p>
 * ApplicationEnvironmentPreparedEvent - 应用环境准备事件
 */

@Slf4j
public class LogMdcListener implements GenericApplicationListener {


    /**
     * 设置当前要监听什么类型的事件
     *
     * @param eventType
     * @return
     */
    @Override
    public boolean supportsEventType(ResolvableType eventType) {
        // ApplicationEnvironmentPreparedEvent来源于springboot
        //A.class.isAssignableFrom(B.class)
        //如果A类型是B类型的父类(接口、同一个类型),则返回true
        //准备加载环境变量事件
        return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType.getRawClass());
    }

    /**
     * 监听到具体事件的处理方法
     *
     * @param event
     */
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        MdcInfo mdcInfo = new MdcInfo();


        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        //准备加载环境变量事件在properties加载之前执行
        //获得当前微服务的名字
        ApplicationEnvironmentPreparedEvent environmentPreparedEvent = (ApplicationEnvironmentPreparedEvent) event;
        //获得配置环境对象
        ConfigurableEnvironment environment = environmentPreparedEvent.getEnvironment();
        //获取属性源集合 - SpringBoot的各种属性来源（application.yml...）
        //打断点
        MutablePropertySources propertySources = environment.getPropertySources();
        //根据断点看到的key复制出name
        PropertySource<?> propertySource = null;

        PropertySource<?> propertySource1 = propertySources.get("applicationConfig: [classpath:/config/bootstrap.yml]");
        if (propertySource1 != null) {
            propertySource = propertySource1;
        } else {
            PropertySource<?> propertySource2 = propertySources.get("applicationConfig: [classpath:/config/application.yml]");
            if (propertySource2 != null) {
                propertySource = propertySource2;
            }
        }
        if (propertySource == null) {
            return;
        }
        PropertySource<?> propertySourceKafka = propertySources.get("applicationConfig: [classpath:/config/application-kafka.yml]");

        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


        String env = propertySource.getProperty("profiles.active") == null ? null : (String) propertySource.getProperty("profiles.active");
        String appName = propertySource.getProperty("appName") == null ? null : (String) propertySource.getProperty("appName");
        PropertySource<?> propertySource3 = null;
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("applicationConfig: [classpath:/config/bootstrap");
        stringBuffer.append("-");
        stringBuffer.append(appName);
        if (StringUtils.isNotBlank(env)) {
            stringBuffer.append("-");
            stringBuffer.append(env);
        }
        stringBuffer.append(".yml]");
        String s = stringBuffer.toString();
        PropertySource<?> propertySource4 = propertySources.get(s);
        if (propertySource4 != null) {
            propertySource3 = propertySource4;
        } else {
            StringBuffer stringBuffer1 = new StringBuffer();
            stringBuffer1.append("applicationConfig: [classpath:/config/application");
            stringBuffer1.append("-");
            stringBuffer1.append(appName);
            if (StringUtils.isNotBlank(env)) {
                stringBuffer1.append("-");
                stringBuffer1.append(env);
            }
            stringBuffer1.append(".yml]");
            String s1 = stringBuffer1.toString();

            PropertySource<?> propertySource5 = propertySources.get(s1);
            if (propertySource5 != null) {
                propertySource3 = propertySource5;
            }
        }

        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

        String logName = propertySource.getProperty("log4j2.logName") == null ? null : (String) propertySource.getProperty("log4j2.logName");
        String logPath = propertySource.getProperty("log4j2.logPath") == null ? null : (String) propertySource.getProperty("log4j2.logPath");
        String rootLevel = propertySource.getProperty("log4j2.rootLevel") == null ? null : (String) propertySource.getProperty("log4j2.rootLevel");
        String rolloverSize = propertySource.getProperty("log4j2.rolloverSize") == null ? null : (String) propertySource.getProperty("log4j2.rolloverSize");

        String applicationName = propertySource.getProperty("applicationName") == null ? null : (String) propertySource.getProperty("applicationName");


        //有值之后进行缓存
        mdcInfo.setLogName(logName);
        mdcInfo.setLogPath(logPath);
        mdcInfo.setRootLevel(rootLevel);
        mdcInfo.setRolloverSize(rolloverSize);

        mdcInfo.setApplicationName(applicationName);


        /**
         * pattern		%X{}
         * 其他		${ctx:}
         */
        //设置MDC
        //ctx: ${ctx:MDCKey}
        //ctx: 固定前缀, 标识MDC中的值
        //MDCKey: java代码中往MDC的TheadLocalMap中配置的Key
        //只在启动时的线程生效，controler被访问时已经是别的线程
        MDC.put("logPath", logPath);
        MDC.put("logName", logName);
        MDC.put("rootLevel", rootLevel);
        MDC.put("rolloverSize", rolloverSize);

        MDC.put("applicationName", applicationName);

        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

        if (propertySource3 == null) {
            return;
        }


        Integer logOutputPort = propertySource3.getProperty("logOutputPort") == null ? null : (Integer) propertySource3.getProperty("logOutputPort");
        mdcInfo.setLogOutputPort(logOutputPort);
        String logOutputHost = propertySource3.getProperty("logOutputHost") == null ? null : (String) propertySource3.getProperty("logOutputHost");
        mdcInfo.setLogOutputHost(logOutputHost);


        Integer kafkaPort = propertySource3.getProperty("kafkaPort") == null ? null : (Integer) propertySource3.getProperty("kafkaPort");
        mdcInfo.setKafkaPort(kafkaPort);
        String kafkaHost = propertySource3.getProperty("kafkaHost") == null ? null : (String) propertySource3.getProperty("kafkaHost");
        mdcInfo.setKafkaHost(kafkaHost);



        MDC.put("logOutputPort", Integer.toString(logOutputPort));
        MDC.put("logOutputHost", logOutputHost);
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        if (propertySourceKafka == null) {
            return;
        }

        StringBuffer buffer = new StringBuffer();
        buffer.append(kafkaHost);
        buffer.append(":");
        buffer.append(kafkaPort);
        String kafkaBootstrapServers = buffer.toString();
        mdcInfo.setKafkaBootstrapServers(kafkaBootstrapServers);
        Integer kafkaConsumerRequestTimeoutMs = propertySourceKafka.getProperty("spring.kafka.consumer.properties.request.timeout.ms") == null ? null : (Integer) propertySourceKafka.getProperty("spring.kafka.consumer.properties.request.timeout.ms");
        mdcInfo.setKafkaConsumerRequestTimeoutMs(kafkaConsumerRequestTimeoutMs);

        MDC.put("kafkaBootstrapServers", kafkaBootstrapServers);
        MDC.put("kafkaConsumerRequestTimeoutMs", Long.toString(kafkaConsumerRequestTimeoutMs));

    }

    /**
     * 控制监听器的顺序 值越小，优先级越高
     *
     * @return
     */
    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE + 19;
    }
}


